package flexo.graphic.entity;

import flexo.graphic.Color;
import flexo.graphic.Font;
import flexo.math.Coords;

public class Text extends DynamicMesh
{
	public enum Align
	{
		LEFT,
		CENTER,
		RIGHT
	}
	
	private Font font;
	private int maxChars;
	private float size;
	private char[] text;
	private boolean update;
	private int maxCharsPerLine;
	private Align align;
	
	public void setAlign(Align align)
	{
		this.align = align;
		update = true;
	}
	
	public void setMaxCharsPerLine(int maxCharsPerLine)
	{
		if (maxCharsPerLine > 0 && maxCharsPerLine <= maxChars)
		{
			this.maxCharsPerLine = maxCharsPerLine;
			update = true;
		}
	}
	
	public Text(Font font, int maxChars)
	{
		flexo.Kernel.log("flexo.graphic.entity.Text", "Creating text");
		
		update = true;
		align = Align.CENTER;
		this.font = font;
		font.grab();
		this.maxChars = maxChars;
		this.maxCharsPerLine = maxChars;
		this.text = new char[maxChars];
		this.size = 1.0f;
		// Each letter uses 4 vertices and 6 indices (a square)
		init(maxChars * 4, maxChars * 6, flexo.graphic.Geometry.UPDATE_SOME);
		
		// Initialize indices
		int j = 0;
		for (int i = 0; i < numIndices; i += 6)
		{
			this.setIndex(i, j);
			this.setIndex(i+1, j+1);
			this.setIndex(i+2, j+2);
			this.setIndex(i+3, j);
			this.setIndex(i+4, j+2);
			this.setIndex(i+5, j+3);
			j += 4;
		}
		setText("");
	}
	
	public void setSize(float size)
	{
		if (size > 0)
		{
			this.size = size;
		}
		update = true;
	}
	
	@ Override
	public void remove()
	{
		font.remove();		
		super.remove();
	}
	
	public void setColor(Color color)
	{
		for (int i = 0; i < numVertices; ++i)
		{
			this.setVertexColor(i, color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
		}
	}
	
	public void setText(String text)
	{
		// Cap the string length to the char limit
		if (text.length() >= maxChars)
		{
			text = text.substring(0, 0 + maxChars);
		}
		
		for (int i = 0; i < maxChars; ++i)
		{
			if (i < text.length())
			{
				this.text[i] = text.charAt(i);
			}
			else
			{
				// Fill the unused positions with null character
				this.text[i] = '\u0000';
			}
		}
		update = true;
	}
	
	public void update()
	{
		if (update)
		{
			this.update = false;
			
			// Update the vertex values
			Coords upperLeft = new Coords();
			Coords lowerRight = new Coords();
			
			float realHeight = size * 0.5f;
			float lineWidth;
			float heightAccum = 0;
			if (maxCharsPerLine == maxChars)
			{
				lineWidth = font.getStringWidth(new String(text)) * size;
			}
			else
			{
				lineWidth = font.getAspectRatio() * size * maxCharsPerLine;
				float fullText = font.getStringWidth(new String(text)) * size;
				heightAccum = (fullText / lineWidth) / 2;
				heightAccum *= size;
			}
			
			float widthAccum = 0;			
			float initialAccum = 0;
			switch (align)
			{
			case LEFT:
				initialAccum = 0;
				break;
			case CENTER:
				initialAccum = - lineWidth / 2.0f;
				break;
			case RIGHT:
				initialAccum = - lineWidth;
				break;
			}
			widthAccum = initialAccum;
			
			for (int i = 0; i < maxChars; ++i)
			{				
				
				boolean makeNewLine = false;
				
				// Word wrap					
				if (Character.isSpaceChar(text[i]))
				{
					float nextWordWidth = 0;
					for (int j = i+1; (j < maxChars) && !Character.isSpaceChar(text[j]); ++j)
					{
						nextWordWidth += size * font.getCharWidth(text[j]);
					}
					
					if ((widthAccum + nextWordWidth) > (initialAccum + lineWidth))
					{
						makeNewLine = true;
					}
				}
				
				font.fillTexCoords(text[i], upperLeft, lowerRight);

				// Upper left vertex
				setVertexPosition((i * 4), widthAccum, heightAccum+realHeight, 0);
				setVertexTexCoord((i * 4), upperLeft.x, upperLeft.y);
				
				// Lower left vertex
				setVertexPosition((i * 4)+1, widthAccum, heightAccum-realHeight, 0);
				setVertexTexCoord((i * 4)+1, upperLeft.x, lowerRight.y);
				
				// If it's a new line and starts with a space character, skip it
				if ( !((widthAccum == initialAccum) && Character.isSpaceChar(text[i])) )
				{
					widthAccum += size * font.getCharWidth(text[i]);
				}
				
				// Lower right vertex
				setVertexPosition((i * 4)+2, widthAccum, heightAccum-realHeight, 0);
				setVertexTexCoord((i * 4)+2, lowerRight.x, lowerRight.y);
				
				// Upper right vertex
				setVertexPosition((i * 4)+3, widthAccum, heightAccum+realHeight, 0);
				setVertexTexCoord((i * 4)+3, lowerRight.x, upperLeft.y);
				
				if (widthAccum > (initialAccum + lineWidth))
				{
					makeNewLine = true;
				}
				
				if (makeNewLine)
				{
					widthAccum = initialAccum;
					heightAccum -= size;
				}				
			}			
			
			// Update the mesh itself
			super.update();			
		}
	}
}
